Passed
Branch master (32b4c5)
by Askupa
01:33
created

Mivhak.component(ꞌvertical-scrollbarꞌ).methods.doScroll   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 21

Duplication

Lines 21
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 5
c 1
b 0
f 1
nc 9
nop 2
dl 21
loc 21
rs 8.7624
1
Mivhak.component('vertical-scrollbar', {
2
    template: '<div class="mivhak-scrollbar mivhak-v-scrollbar"><div class="mivhak-scrollbar-thumb"></div></div>',
3
    props: {
4
        editor: null,
5
        $inner: null,
6
        $outer: null,
7
        mivhakInstance: null,
8
        minHeight: 50,
9
        state: {
10
            a: 0,    // The total height of the editor
11
            b: 0,    // The height of the viewport, excluding padding
12
            c: 0,    // The height of the viewport, including padding
13
            d: 0,    // The calculated thumb height
14
            t: 0     // The current top offset of the viewport
15
        },
16
        initialized: false
17
    },
18
    methods: {
19
        initialize: function() {
20
            if(!this.initialized)
21
            {
22
                this.initialized = true;
23
                this.dragDealer();
24
                var $this = this;
25
                this.$inner.on('mousewheel', function(e){$this.onScroll.call(this, e);});
26
                $(window).resize(function(){
27
                    if($this.mivhakInstance.state.lineWrap)
28
                        $this.refresh();
29
                });
30
            }
31
            // Refresh anytime initialize is called
32
            this.refresh();
33
        },
34
        updateState: function() {
35
            var oldState = $.extend({}, this.state);
36
            this.state.a = getEditorHeight(this.$inner);
37
            this.state.b = this.mivhakInstance.state.height;
38
            this.state.c = this.mivhakInstance.state.height-this.mivhakInstance.options.padding*2;
39
            this.state.d = Math.max(this.state.c*this.state.b/this.state.a,this.minHeight);
40
            this.state.t *=  this.state.a/Math.max(oldState.a,1); // Math.max used to prevent division by zero
41
            return this.state.a !== oldState.a || this.state.b !== oldState.b;
42
        },
43
        refresh: function() {
44
            var $this = this, oldTop = this.state.t;
45
            raf(function(){
46
                if($this.updateState())
47
                {
48
                    if($this.getDifference() > 0)
49
                    {
50
                        $this.doScroll('up',oldTop-$this.state.t);
51
                        $this.$el.css({height: $this.state.d + 'px', top: 0});
52
                        $this.moveBar();
53
                    }
54
                    else 
55
                    {
56
                        $this.doScroll('up',$this.state.t);
57
                        $this.$el.css({height: 0});
58
                    }
59
                }
60
            });
61
        },
62
        onScroll: function(e) {
63
            var didScroll;
64
            
65
            if(e.deltaY > 0)
66
                didScroll = this.doScroll('up',e.deltaY*e.deltaFactor);
67
            else
68
                didScroll = this.doScroll('down',-e.deltaY*e.deltaFactor);
69
            
70
            if(0 !== didScroll) {
71
                this.moveBar();
72
                e.preventDefault(); // Only prevent page scroll if the editor can be scrolled
73
            }
74
        },
75
        dragDealer: function(){
76
            var $this = this,
77
                lastPageY;
78
79
            this.$el.on('mousedown.drag', function(e) {
80
                lastPageY = e.pageY;
81
                $this.$el.add(document.body).addClass('mivhak-scrollbar-grabbed');
82
                $(document).on('mousemove.drag', drag).on('mouseup.drag', stop);
83
                return false;
84
            });
85
86
            function drag(e){
87
                var delta = e.pageY - lastPageY,
88
                    didScroll;
89
            
90
                // Bail if the mouse hasn't moved
91
                if(!delta) return;
92
            
93
                lastPageY = e.pageY;
94
                
95
                raf(function(){
96
                    didScroll = $this.doScroll(delta > 0 ? 'down' : 'up', Math.abs(delta*getEditorHeight($this.$inner)/$this.$outer.parent().height()));
97
                    if(0 !== didScroll) $this.moveBar();
98
                });
99
            }
100
101
            function stop() {
102
                $this.$el.add(document.body).removeClass('mivhak-scrollbar-grabbed');
103
                $(document).off("mousemove.drag mouseup.drag");
104
            }
105
        },
106
        moveBar: function() {
107
            this.$el.css({
108
                top:  (this.state.b-this.state.d)/(this.state.a-this.state.c)*this.state.t + 'px'
109
            });
110
        },
111
        
112
        /**
113
         * Scrolls the editor element in the direction given, provided that there 
114
         * is remaining scroll space
115
         * @param {string} dir
116
         * @param {int} delta
117
         */
118
        doScroll: function(dir, delta) {
119
            var s = this.state,
120
                remaining,
121
                didScroll;
122
            
123
            if('up' === dir) 
124
            {
125
                remaining = s.t;
126
                didScroll = remaining > 0 ? Math.min(remaining,delta) : 0;
127
                s.t -= didScroll;
128
            }
129
            if('down' === dir) 
130
            {
131
                remaining = this.getDifference() - s.t;
132
                didScroll = remaining > 0 ? Math.min(remaining,delta) : 0;
133
                s.t += didScroll;
134
            }
135
            
136
            this.$inner.css({top: -s.t});
137
            return didScroll;
138
        },
139
        
140
        /**
141
         * Returns the difference between the containing div and the editor div
142
         */
143
        getDifference: function()
144
        {
145
            return this.state.a - this.state.c;
146
        }
147
    }
148
});